package com.foftact.etfrank.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.foftact.etfrank.ETFRank;
import com.foftact.etfrank.mapper.ETFRankMapper;
import com.foftact.etfrank.service.ETFRankService;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * ETF排行服务实现类
 */
@Service
public class ETFRankServiceImpl implements ETFRankService {

    private static final Logger logger = LoggerFactory.getLogger(ETFRankServiceImpl.class);

    private static final String API_URL = "https://fund.eastmoney.com/data/rankhandler.aspx";
    private static final String DATA_SOURCE = "eastmoney";
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    @Autowired
    private ETFRankMapper etfRankMapper;

    @Override
    @Transactional
    public int fetchAndSaveETFRankData() {
        logger.info("fetch start 开始抓取ETF排行数据");
        int totalCount = 0;
        int pageIndex = 1;
        int pageSize = 50;
        boolean hasMoreData = true;

        try {
            while (hasMoreData) {
                List<ETFRank> etfRankList = fetchETFRankDataByPage(pageIndex, pageSize);
                logger.info("fetch begin 开始处理第{}页数据{}条", pageIndex, pageSize);
                logger.info("{}", JSON.toJSONString(etfRankList, JSONWriter.Feature.PrettyFormat));
                if (etfRankList.isEmpty()) {
                    hasMoreData = false;
                } else {
                    int count = saveETFRankBatch(etfRankList);
                    totalCount += count;
                    logger.info("fetch end 第{}页数据处理完成，保存{}条记录", pageIndex, count);
                    pageIndex++;
                    // 为了避免频繁请求，添加适当的延迟
                    Thread.sleep(1000);
                }
            }
            logger.info("fetch finish ETF排行数据抓取完成，共保存{}条记录", totalCount);
        } catch (Exception e) {
            logger.error("抓取ETF排行数据失败", e);
            throw new RuntimeException("抓取ETF排行数据失败", e);
        }
        return totalCount;
    }

    @Override
    public List<ETFRank> fetchETFRankDataByPage(int pageIndex, int pageSize) {
        List<ETFRank> etfRankList = new ArrayList<>();
        String url = buildApiUrl(pageIndex, pageSize);

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(url);
            httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
            httpGet.addHeader("Referer", "https://fund.eastmoney.com/data/fbsfundranking.html");

            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String responseBody = EntityUtils.toString(entity, "UTF-8");
                    etfRankList = parseRankData(responseBody);
                }
            }
        } catch (Exception e) {
            logger.error("抓取第{}页ETF排行数据失败", pageIndex, e);
        }

        return etfRankList;
    }

    @Override
    public boolean saveETFRank(ETFRank etfRank) {
        try {
            // 检查数据是否已存在
            ETFRank existing = etfRankMapper.selectByCodeAndDate(
                    etfRank.getFundCode(), etfRank.getNavDate());

            if (existing != null) {
                // 更新数据
                etfRank.setId(existing.getId());
                int result = etfRankMapper.updateByCodeAndDate(etfRank);
                return result > 0;
            } else {
                // 新增数据
                int result = etfRankMapper.insert(etfRank);
                return result > 0;
            }
        } catch (Exception e) {
            logger.error("保存ETF排行数据失败", e);
            return false;
        }
    }

    @Override
    @Transactional
    public int saveETFRankBatch(List<ETFRank> etfRankList) {
        if (etfRankList == null || etfRankList.isEmpty()) {
            return 0;
        }

        try {
            // 设置通用属性
            String dataSource = DATA_SOURCE;
            Date currentDate = new Date();
            for (ETFRank etfRank : etfRankList) {
                etfRank.setDataSource(dataSource);
            }

            // 批量插入或更新
            int result = etfRankMapper.batchInsert(etfRankList);
            return result;
        } catch (Exception e) {
            logger.error("批量保存ETF排行数据失败", e);
            return 0;
        }
    }

    @Override
    public ETFRank getETFRankByCodeAndDate(String fundCode, Date navDate) {
        return etfRankMapper.selectByCodeAndDate(fundCode, navDate);
    }

    @Override
    public List<ETFRank> getETFRankByDate(Date navDate) {
        return etfRankMapper.selectByDate(navDate);
    }

    @Override
    public List<ETFRank> getRecentETFRank(int days) {
        return etfRankMapper.selectRecentDays(days);
    }

    @Override
    public List<ETFRank> getAllETFRank() {
        return etfRankMapper.selectAll();
    }

    @Override
    public List<ETFRank> getETFRankByGrowthRate(String orderByField, String orderByDirection, Integer limit) {
        // 验证排序字段的合法性
        List<String> validOrderFields = Arrays.asList(
                "weekly_growth_rate", "monthly_growth_rate", "quarterly_growth_rate",
                "semiannual_growth_rate", "yearly_growth_rate", "two_year_growth_rate",
                "three_year_growth_rate"
        );

        if (!validOrderFields.contains(orderByField)) {
            // 默认按近1周增长率排序
            orderByField = "weekly_growth_rate";
        }

        // 验证排序方向
        if (!"asc".equalsIgnoreCase(orderByDirection) && !"desc".equalsIgnoreCase(orderByDirection)) {
            orderByDirection = "desc";
        }

        return etfRankMapper.selectByRank(orderByField, orderByDirection, limit);
    }

    @Override
    public int cleanOldETFRankData(Date date) {
        return etfRankMapper.deleteBeforeDate(date);
    }

    /**
     * 构建API请求URL
     */
    private String buildApiUrl(int pageIndex, int pageSize) {
        StringBuilder urlBuilder = new StringBuilder(API_URL);
        urlBuilder.append("?op=ph&dt=fb&ft=ct&rs=&gs=0&sc=zzf&st=desc");
        urlBuilder.append("&pi=").append(pageIndex);
        urlBuilder.append("&pn=").append(pageSize);
        // 添加随机参数以避免缓存
        urlBuilder.append("&v=").append(Math.random());
        return urlBuilder.toString();
    }

    /**
     * 解析排行数据
     */
    private List<ETFRank> parseRankData(String responseBody) {
        List<ETFRank> etfRankList = new ArrayList<>();

        try {
            // 提取JSON数据部分
            int startIndex = responseBody.indexOf("{");
            int endIndex = responseBody.lastIndexOf("}") + 1;
            if (startIndex > 0 && endIndex > startIndex) {
                String jsonStr = responseBody.substring(startIndex, endIndex);
                JSONObject jsonObject = JSON.parseObject(jsonStr, JSONReader.Feature.AllowUnQuotedFieldNames);

                if (jsonObject.containsKey("datas")) {
                    List<String> datas = jsonObject.getJSONArray("datas").toJavaList(String.class);

                    for (String data : datas) {
                        String[] fields = data.split(",");
                        if (fields.length >= 14) {
                            ETFRank etfRank = new ETFRank();
                            etfRank.setFundCode(fields[0]);
                            etfRank.setFundName(fields[1]);
                            etfRank.setFundFullName(fields[2]);

                            // 解析日期
                            try {
                                etfRank.setNavDate(DATE_FORMAT.parse(fields[3]));
                            } catch (ParseException e) {
                                logger.warn("解析日期失败: {}", fields[3]);
                                continue;
                            }

                            // 解析数值字段
                            etfRank.setUnitNav(parseBigDecimal(fields[4]));
                            etfRank.setCumulativeNav(parseBigDecimal(fields[5]));
                            etfRank.setWeeklyGrowthRate(parseBigDecimal(fields[6]));
                            etfRank.setMonthlyGrowthRate(parseBigDecimal(fields[7]));
                            etfRank.setQuarterlyGrowthRate(parseBigDecimal(fields[8]));
                            etfRank.setSemiannualGrowthRate(parseBigDecimal(fields[9]));
                            etfRank.setYearlyGrowthRate(parseBigDecimal(fields[10]));
                            etfRank.setTwoYearGrowthRate(parseBigDecimal(fields[11]));
                            etfRank.setThreeYearGrowthRate(parseBigDecimal(fields[12]));

                            // 基金类型
                            if (fields.length > 13) {
                                etfRank.setFundType(fields[13]);
                            }

                            etfRankList.add(etfRank);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("解析ETF排行数据失败", e);
        }

        return etfRankList;
    }

    /**
     * 解析BigDecimal值
     */
    private BigDecimal parseBigDecimal(String value) {
        if (value == null || value.isEmpty()) {
            return null;
        }
        try {
            // 移除百分号（如果有）
            String cleanValue = value.replace("%", "");
            return new BigDecimal(cleanValue);
        } catch (NumberFormatException e) {
            logger.warn("解析数值失败: {}", value);
            return null;
        }
    }
}